﻿using System;
using System.Collections.Generic;
using System.Text;

namespace Arcana.Contract.Property
{
    /// <summary>
    /// Abstracts <see cref="Property.ContractBase"/> class to develop contracts that perform universal or existential
    /// quantification on enumerable properties.
    /// </summary>
    /// <remarks>
    /// This class provides two important nested subclasses, which are used to easily develop contracts that perform
    /// universal or existential quatification on properties that are expected to be of type <see cref="System.Collections.IEnumerable"/>.
    /// If the specified property is not an instance of <see cref="System.Collections.IEnumerable"/> an exception of type
    /// <see cref="System.propertyException"/> is thrown.
    /// </remarks>
    public static class EnumerableContractBase
    {
        /// <summary>
        /// Abstracts <see cref="Property.ContractBase"/> class to develop contracts that perform universal quantification
        /// on enumerable properties.
        /// </summary>
        /// <remarks>
        /// As contracts inherited from this class, perform universal quantification, all items in <i>property</i> should be validated with
        /// <see cref="ValidateItem"/> abstract method. <br />
        /// This class abstracts away <see cref="property.ContractBase"/> class to provide an easier way to develop contracts that perform a universal
        /// quantification on a property of type <see cref="System.Collections.IEnumerable"/>. <br />
        /// <b>Note to Implementers:</b> Implementing <see cref="ValidateItem"/> is necessary and sufficient in order for the contract to be specified.
        /// If the <i>item</i> in an enumerable <i>property</i> of type <see cref="System.Collections.IEnumerable"/> is validated, then, a value of
        /// <b>true</b> should be returned, otherwise, a value of <b>false</b> should be returned.
        /// </remarks>
        [Serializable]
        public abstract class UniversalQuantification : ContractBase
        {
            /// <summary>
            /// Performs validation on the property.
            /// </summary>
            /// <param name="property">The property that should be validated.</param>
            /// <exception cref="ArgumentException"> <i>property</i> is not of type <see cref="System.Collection.IEnumerable"/>. </exception>
            /// <exception cref="ArgumentNullException"> <i>property</i> is <b>null</b>. </exception>
            /// <returns><b>true</b> if <i>property</i> is validated, otherwise <b>false</b>.</returns>
            protected sealed override bool ValidateProperty(object property)
            {
                if (property.GetType().GetInterface("IEnumerable") == null)
                    throw new ArgumentException();
                if (property == null)
                    throw new ArgumentNullException();
                System.Collections.IEnumerable _property = (System.Collections.IEnumerable)property;
                foreach (var item in _property)
                {
                    if (!ValidateItem(item)) return false;
                }
                return true;
            }

            /// <summary>
            /// Performs validation on an item which is stored in an property of type <see cref="System.Collections.IEnumerable"/>.
            /// </summary>
            /// <remarks>
            /// <b>Note: </b>The target property must be of type <see cref="System.Collection.IEnumerable"/>. Otherwise
            /// <see cref="System.ArgumentException"/> is thrown in validation time. <br />
            /// As contracts inherited from this class, perform universal quantification, all items in <i>property</i> should be validated. <br />
            /// <b>Note to Implementers:</b> Implementing <see cref="ValidateItem"/> is necessary and sufficient in order for the contract to be specified.
            /// If the <i>item</i> in an enumerable <i>property</i> of type <see cref="System.Collections.IEnumerable"/> is validated, then, a value of
            /// <b>true</b> should be returned, otherwise, a value of <b>false</b> should be returned.
            /// </remarks>
            /// <param name="item">The item should be validated.</param>
            /// <returns><b>true</b> if <i>item</i> is validated, otherwise <b>false</b>.</returns>
            protected abstract bool ValidateItem(object item);
        }

        /// <summary>
        /// Abstracts <see cref="Property.ContractBase"/> class to develop contracts that perform existential quantification
        /// on enumerable properties.
        /// </summary>
        /// <remarks>
        /// As contracts inherited from this class, perform existential quantification, at least one item in an <i>property</i> should be validated with
        /// <see cref="ValidateItem"/> abstract method. <br />
        /// This class abstracts away <see cref="Property.ContractBase"/> class to provide an easier way to develop contracts that perform an existential
        /// quantification on an property of type <see cref="System.Collections.IEnumerable"/>. <br />
        /// <b>Note to Implementers:</b> Implementing <see cref="ValidateItem"/> is necessary and sufficient in order for the contract to be specified.
        /// If the <i>item</i> in an enumerable <i>property</i> of type <see cref="System.Collections.IEnumerable"/> is validated, then, a value of
        /// <b>true</b> should be returned, otherwise, a value of <b>false</b> should be returned.
        /// </remarks>
        [Serializable]
        public abstract class ExistentialQuatification : ContractBase
        {
            /// <summary>
            /// Performs validation on the property.
            /// </summary>
            /// <param name="property">The property that should be validated.</param>
            /// <exception cref="ArgumentException"> <i>property</i> is not of type <see cref="System.Collection.IEnumerable"/>. </exception>
            /// <exception cref="ArgumentNullException"> <i>property</i> is <b>null</b>. </exception>
            /// <returns><b>true</b> if <i>property</i> is validated, otherwise <b>false</b>.</returns>
            protected sealed override bool ValidateProperty(object property)
            {
                if (property.GetType().GetInterface("IEnumerable") == null)
                    throw new ArgumentException();
                if (property == null)
                    throw new ArgumentNullException();
                System.Collections.IEnumerable _property = (System.Collections.IEnumerable)property;
                foreach (var item in _property)
                {
                    if (!ValidateItem(item)) return true;
                }
                return false;
            }

            /// <summary>
            /// Performs validation on an item which is stored in an property of type <see cref="System.Collections.IEnumerable"/>.
            /// </summary>
            /// <remarks>
            /// <b>Note: </b>The target property must be of type <see cref="System.Collection.IEnumerable"/>. Otherwise
            /// <see cref="System.propertyException"/> is thrown in validation time. <br />
            /// As contracts inherited from this class, perform existential quantification, at least one item in <i>property</i> should be validated. <br />
            /// <b>Note to Implementers:</b> Implementing <see cref="ValidateItem"/> is necessary and sufficient in order for the contract to be specified.
            /// If the <i>item</i> in an enumerable <i>property</i> of type <see cref="System.Collections.IEnumerable"/> is validated, then, a value of
            /// <b>true</b> should be returned, otherwise, a value of <b>false</b> should be returned.
            /// </remarks>
            /// <param name="item">The item should be validated.</param>
            /// <returns><b>true</b> if <i>item</i> is validated, otherwise <b>false</b>.</returns>
            protected abstract bool ValidateItem(object item);
        }
    }
}
